package com.nc.delivery_project.server;

import com.nc.delivery_project.server.domain.*;
import com.nc.delivery_project.server.domain.Currency;
import com.nc.delivery_project.server.service.*;

import java.sql.Timestamp;
import java.text.DecimalFormat;
import java.util.*;

/**
 * Created by miroshnik on 1/23/2015.
 */
public class FillDb {
    
    private static Random rnd = new Random();
    
    public static void main(String[] args) {
        createRoles();
        createCurrency();

        createCities(10);
        createDepartments(10);

        createUsers(50);
        createPersons();
        createContacts(10);

        createSchedules(50, true);
        createPayments(50);
        createOrderWaypoints(50);
        createOrdersWithCargoes(20);

    }

    private static void createOrdersWithCargoes(int count) {
        int orderid;
        Timestamp sent = getRandomDate("2014-01-01 00:00:00", "2015-01-01 00:00:00");
        Timestamp received = getRandomDate("2014-01-01 00:00:00", "2015-01-01 00:00:00");
        List<OrderWaypoint> orderWaypoints = new OrderWaypointService().read();
        List<Currency> currencies = new CurrencyService().read();
        CargoService cargoService = new CargoService();
        List<User> users = new UserService().read();
        List<Payment> payments = new PaymentService().read();
        OrderService service = new OrderService();
        ArrayList<Cargo> tmpCargoes = new ArrayList<Cargo>();
        ArrayList<OrderWaypoint> tmpOrderWaypoints = new ArrayList<OrderWaypoint>();
        Order order = new Order();
        for (int i = 0; i < count; i++) {
            order.setSender(users.get(rnd.nextInt(users.size())));
            order.setReceiver(users.get(rnd.nextInt(users.size())));
            order.setPayment(payments.get(rnd.nextInt(payments.size())));

            //иногда будет ставить случайный комментарий
            if (rnd.nextBoolean())
                order.setComment(getRandomString(getRandomInt(70, 400)));

            //получает случайную дату отправки
            Timestamp sendTimestamp = getRandomDate("2014-01-01 00:00:00", "2015-02-30 00:00:00");
            Date sentDate = new Date(sendTimestamp.getTime());

           order.setStartDate(sentDate.toString());  //java.sql.SQLDataException: ORA-01841: (full) year must be between -4713 and +9999, and not be 0
              order.setStartDate(sent.toString());//sorry

            //добавляем к дате отправки от 0 до 32 дней (рандомно) и получаем дату прибытия
            Calendar receivedDate = addDays(sendTimestamp, rnd.nextInt(33)+1);

          //  order.setDeliveryDate(receivedDate.toString()); sorry again
            order.setDeliveryDate(received.toString());

            //если дата отправки больше чем сегодняшняя дата, то ставим заказу статутс "подтвержден"
            if (sentDate.compareTo(new Date()) > 0) {
                order.setStatus(OrderStatus.CONFIRMED.name().toLowerCase());
            } else if (receivedDate.compareTo(Calendar.getInstance()) > 0) {    //если дата получения меньше чем сегодня, то - заказ в процессе
                order.setStatus(OrderStatus.PROCESS.name().toLowerCase());
            } else {    //иначе заказ завершен
                order.setStatus(OrderStatus.FINISHED.name().toLowerCase());
            }

            orderid=service.create(order);
            System.out.println("Order created");
        
            for (int j=0; j<3; j++)
            {
                Cargo cargo = new Cargo();

                cargo.setCurrency(currencies.get(rnd.nextInt(currencies.size())));
                cargo.setCost(rnd.nextInt(3000));
                cargo.setTitle("testCargo" + j);
                cargo.setWeight(rnd.nextInt(50));
                cargo.setWidth(rnd.nextInt(3));
                cargo.setHeight(rnd.nextInt(3));
                cargo.setDepth(rnd.nextInt(3));
               // cargo.setId(j * 100);
                cargo.setOrderId(orderid);
                cargoService.create(cargo);
                System.out.println("Cargo created");
                tmpCargoes.add(cargo);
                tmpOrderWaypoints.add(orderWaypoints.get(rnd.nextInt(orderWaypoints.size())));
            }
            order.setCargoes(tmpCargoes);
            order.setOrderWaypoints(tmpOrderWaypoints);
		}


    }

    public static List<Schedule> createSchedules(int count, boolean fillDb) {
        List<Currency> currencyList = new CurrencyService().read();
        List<LegalPerson> persons = new LegalPersonService().read();
        List<LegalPerson> transporters = new ArrayList<>();
        List<Department> departments = new DepartmentService().read();
        ScheduleService scheduleService = new ScheduleService();
        List<Schedule> scheduleList = new ArrayList<>();

        for (LegalPerson person : persons) {
            if (person.getRole().getTitle().equals("transporter")) {
                transporters.add(person);
            }
        }

        for (int i = 0; i < count; i++) {
            Timestamp tariffDate = getRandomDate("2014-01-01 00:00:00", "2015-01-01 00:00:00");
            Timestamp departureDate = getRandomDate("2015-01-01 00:00:00", "2015-07-07 00:00:00");

            Calendar cal = Calendar.getInstance();
            cal.setTime(departureDate);
            cal.add(Calendar.DAY_OF_WEEK, rnd.nextInt(33));
            Timestamp arrivalDate = new Timestamp(cal.getTime().getTime());
            
            Schedule schedule = new Schedule();
            schedule.setOrigin(departments.get(rnd.nextInt(departments.size())));
            schedule.setDestination(departments.get(rnd.nextInt(departments.size())));
            schedule.setTransportCompany(transporters.get(rnd.nextInt(transporters.size())));
            schedule.setPrimeCost(getRandomInt(100, 1000));
            schedule.setSellingRate(rnd.nextDouble());
            
            schedule.setTariffDate(tariffDate);
            schedule.setDepartureDate(departureDate);
            schedule.setArrivalDate(arrivalDate);

            schedule.setCurrency(currencyList.get(rnd.nextInt(currencyList.size())));

            scheduleList.add(schedule);

            if (fillDb)
                scheduleService.create(schedule);

            System.out.println("schedule created");
        }

        return scheduleList;
    }

    /**
     * должны быть созданы страны и стейтпровинс 
     * @param count
     */
    private static void createCities(int count) {
        List<StateProvince> states = new StateProvinceService().read();
        CityService cityService = new CityService();
        
        for (int i = 0; i < count; i++) {
            City city = new City();
            city.setCityTitle("city" + i);
            city.setStatePr(states.get(rnd.nextInt(states.size())));
            
            cityService.create(city);

            System.out.println("City created");
        }
    }

    /**
     * должны быть созданы города 
     * @param count
     */
    private static void createDepartments(int count) {
        List<City> cities = new CityService().read();
        DepartmentService departmentService = new DepartmentService();

        for (int i = 0; i < count; i++) {
            Department department = new Department();
            department.setAddress("address" + i);
            department.setPostalCode("postal_code" + i);
            department.setCity(cities.get(rnd.nextInt(cities.size())));
            
            departmentService.create(department);

            System.out.println("Department created");
        }
        
    }

    /**
     * должны быть созданы роли 
     * @param count
     */
    private static void createUsers(int count) {
        List<Role> roles = new RoleService().read();
        UserService userService = new UserService();

        for (int i = 0; i < count; i++) {
            User user = new User();
            user.setEmail("email" + i + "@gmail.com");
            user.setPassword("password");
            user.setRole(roles.get(rnd.nextInt(roles.size())));
            
            userService.create(user);
            System.out.println("User created");
        }
        
    }

    /**
     * должны быть созданы юзеры 
     */
    private static void createPersons() {
        NaturalPersonService naturalPersonService = new NaturalPersonService();
        LegalPersonService legalPersonService = new LegalPersonService();
        List<User> users = new UserService().read();
        for (int i = 0; i < users.size(); i++) {
            User user = users.get(i);
            String roleTitle = user.getRole().getTitle();
            switch (roleTitle) {
                case "transporter":
                    LegalPerson transporter = new LegalPerson();
                    transporter.setTitle("transporter" + i);
                    transporter.setId(user.getId());
                    transporter.setEmail(user.getEmail());
                    transporter.setPassword(user.getPassword());
                    legalPersonService.create(transporter);
                    System.out.println("Transporter created: " + transporter);
                    break;
                case "admin":
                    NaturalPerson admin = new NaturalPerson(user.getId(), "admin" + i, getRandomTel());
                    admin.setEmail(user.getEmail());
                    admin.setRole(user.getRole());
                    admin.setPassword(user.getPassword());
                    naturalPersonService.create(admin);
                    System.out.println("admin created: " + admin);
                    break;
                case "operator":
                    NaturalPerson operator = new NaturalPerson(user.getId(), "operator" + i, getRandomTel());
                    operator.setEmail(user.getEmail());
                    operator.setRole(user.getRole());
                    operator.setPassword(user.getPassword());
                    naturalPersonService.create(operator);
                    System.out.println("operator created: " + operator);
                    break;
                case "user":
                    boolean flag = rnd.nextBoolean();
                    if (flag) {
                        NaturalPerson naturalPerson = new NaturalPerson(user.getId(), "naturalPerson" + i, getRandomTel());
                        naturalPerson.setEmail(user.getEmail());
                        naturalPerson.setRole(user.getRole());
                        naturalPerson.setPassword(user.getPassword());
                        naturalPersonService.create(naturalPerson);
                        System.out.println("NaturalPerson created: " + naturalPerson);
                    } else {
                        LegalPerson legalPerson = new LegalPerson();
                        legalPerson.setTitle("company" + i);
                        legalPerson.setId(user.getId());
                        legalPerson.setEmail(user.getEmail());
                        legalPerson.setPassword(user.getPassword());
                        legalPerson.setRole(user.getRole());
                        legalPersonService.create(legalPerson);
                        System.out.println("LegalPerson created: " + legalPerson);
                    }
                    break;
            }
        }
    }

    /**
     * должны быть созданы legalperson
     */
    private static void createContacts(int contactsBoundPerLegalPerson) {
        LegalPersonService service = new LegalPersonService();
        ContactService contactService = new ContactService();
        List<LegalPerson> legalPersons = service.read();

        for (int i = 0; i < legalPersons.size(); i++) {
            int contactCount = rnd.nextInt(contactsBoundPerLegalPerson);

            for (int j = 0; j < contactCount; j++) {
                ContactName contact = new ContactName();
                contact.setPersonId(legalPersons.get(i).getLegalPersonId());
                contact.setEmail("contact_email" + i+j + "@gmail.com");
                contact.setFullName("contact name" + i+j);
                contact.setTel(getRandomTel());
                
                contactService.create(contact);

                System.out.println("ContactName created: " + contact.toString());
            }
        }
    }
    private static void createPayments(int count)
    {
        Timestamp incoming = getRandomDate("2014-01-01 00:00:00", "2015-01-01 00:00:00");
        List<Currency> currencies = new CurrencyService().read();
        PaymentService paymentService = new PaymentService();

        for (int i = 0; i < count; i++) {
            Payment payment = new Payment();
            payment.setAmount((double) getRandomInt(100, 10000));
            // payment.setId((long)i+9000);
            payment.setCurrency(currencies.get(rnd.nextInt(currencies.size())));
            payment.setIncomingDate(incoming.toString());
            paymentService.create(payment);
            System.out.println("Payment created: " + payment);
        }
    }
    private static void createRoles() {
        RoleService service = new RoleService();
        Role role = new Role("admin");
        service.create(role);
        
        role.setTitle("operator");
        service.create(role);
        
        role.setTitle("transporter");
        service.create(role);
        
        role.setTitle("user");
        service.create(role);
    }
    private static  void createOrderWaypoints(int count)
    {
        Timestamp recievedDate = getRandomDate("2014-01-01 00:00:00", "2015-01-01 00:00:00");
        Timestamp sentDate = getRandomDate("2014-01-01 00:00:00", "2015-01-01 00:00:00");
        List<Department> departments = new DepartmentService().read();
        OrderWaypointService service = new OrderWaypointService();
        for (int i=0; i<count; i++)
        {
            OrderWaypoint orderWaypoint = new OrderWaypoint();
            orderWaypoint.setDepartment(departments.get(rnd.nextInt(departments.size())));
            //orderWaypoint.setId(i+3000);
            orderWaypoint.setPriority(rnd.nextInt(10));
            orderWaypoint.setReceivedDate(recievedDate);
            orderWaypoint.setSentDate(sentDate);
            orderWaypoint.setStatus("ready");
            service.create(orderWaypoint);
            System.out.println("OrderWaypoint created");
        }
    }
    private static void createCurrency() {
        CurrencyService service = new CurrencyService();
        Currency currency = new Currency();
        currency.setTitle("USD");
        currency.setRate(1);
        service.create(currency);
        
        currency.setTitle("UAH");
        currency.setRate(0.0625);
        service.create(currency);
        
        currency.setTitle("EUR");
        currency.setRate(1.13);
        service.create(currency);
    }
    
    private static String getRandomTel() {
        Random rand = new Random();
        int num1 = (rand.nextInt(7) + 1) * 100 + (rand.nextInt(8) * 10) + rand.nextInt(8);
        int num2 = rand.nextInt(743);
        int num3 = rand.nextInt(10000);

        DecimalFormat df3 = new DecimalFormat("000"); // 3 zeros
        DecimalFormat df4 = new DecimalFormat("0000"); // 4 zeros

        return df3.format(num1) + "-" + df3.format(num2) + "-" + df4.format(num3);
    }
	public static String getRandomString(int length) {
        String characters = "abcdefghiklmnopqrstvxyz ";
        Random rand = new Random();
        char[] text = new char[length];
        for (int i = 0; i < length; i++) {
            text[i] = characters.charAt(rand.nextInt(characters.length()));
        }

        return new String(text);
    }
    private static Timestamp getRandomDate(String offset, String end) {
        long offsetL = Timestamp.valueOf(offset).getTime();
        long endL = Timestamp.valueOf(end).getTime();
        long diff = endL - offsetL + 1;
        return new Timestamp(offsetL + (long)(Math.random() * diff));
    }
    
    private static int getRandomInt(int min, int max) {
        Random rand = new Random();
        return rand.nextInt((max - min) + 1) + min;
    }
    public static Calendar addDays(Timestamp date, int daysCount) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.DAY_OF_WEEK, rnd.nextInt(daysCount));

        return cal;
    }
}
